package com.mazaiting.generator.service.impl;

import cn.hutool.core.text.NamingCase;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mazaiting.common.core.domain.result.ResultCode;
import com.mazaiting.common.core.ex.exceptions.BusinessException;
import com.mazaiting.common.core.ex.exceptions.EmptyObjectException;
import com.mazaiting.common.core.utils.DateTimeUtil;
import com.mazaiting.generator.config.GenDataSource;
import com.mazaiting.generator.config.GeneratorProperties;
import com.mazaiting.generator.constants.GenConstant;
import com.mazaiting.generator.domain.entity.*;
import com.mazaiting.generator.domain.info.BaseClassInfo;
import com.mazaiting.generator.domain.info.FieldInfo;
import com.mazaiting.generator.domain.info.FieldTypeInfo;
import com.mazaiting.generator.domain.query.PreviewQuery;
import com.mazaiting.generator.domain.query.TableQuery;
import com.mazaiting.generator.domain.vo.PreviewVO;
import com.mazaiting.generator.domain.vo.TableDefaultVO;
import com.mazaiting.generator.domain.vo.TableVO;
import com.mazaiting.generator.enums.FormTypeEnum;
import com.mazaiting.generator.service.*;
import com.mazaiting.generator.utils.GenUtil;
import com.mazaiting.generator.utils.TemplateUtil;
import com.mazaiting.mybatisplus.domain.vo.BasePageVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 数据表
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TableServiceImpl implements ITableService {
    private final GeneratorProperties generatorProperties;
    private final IDatasourceService dataSourceService;
    private final IFieldTypeService fieldTypeService;
    private final IBaseClassService baseClassService;
    private final IProjectService projectService;
    private final ITemplateGroupService templateGroupService;
    private final ITemplateFileService templateFileService;
    private final IPropItemService propItemService;

    @Override
    public BasePageVO<TableVO> page(TableQuery tableQuery) throws Exception {
        // 初始化配置信息
        GenDataSource dataSource = dataSourceService.getBySourceId(tableQuery.getDatasourceId());
        // 获取数据库表列表
        List<TableVO> tableList = GenUtil.getTableList(dataSource);

        //当前页码
        int pageNum = tableQuery.getPageNum();
        //每页条数
        int pageSize = tableQuery.getPageSize();
        //忽略上一页，如果是第一页肯定不用忽略
        int skipNum = pageSize * (pageNum - 1);
        List<TableVO> tableVOList = tableList.stream()
                .filter(tableVO -> {
                    // 表名, 模糊查询
                    String tableName = tableQuery.getTableName();
                    if (StringUtils.hasLength(tableName)) {
                        return tableVO.getName().contains(tableName);
                    }
                    return true;
                }).toList();

        // 获取子列表
        List<TableVO> subTableVOList = tableVOList.stream()
                .skip(skipNum)
                .limit(pageSize)
                .toList();

        // 分页数据
        BasePageVO<TableVO> basePageVO = new BasePageVO<>();
        basePageVO.setTotal((long) tableVOList.size());
        basePageVO.setList(subTableVOList);

        return basePageVO;
    }

    @Override
    public PreviewVO getContentByFileType(PreviewQuery previewQuery) throws BusinessException, EmptyObjectException {
        // 模板文件 ID
        Long templateFileId = previewQuery.getTemplateFileId();
        // 根据 ID 查询文件
        TemplateFileEntity templateFileEntity = templateFileService.getById(templateFileId);
        if (Objects.isNull(templateFileEntity)) {
            throw new EmptyObjectException(ResultCode.COMMON_FAIL.getCode(), "模板 ID 不存在");
        }
        try {
            // 数据模型
            Map<String, Object> dataModel = getDataModel(previewQuery);
            // 模板名
            String templateName = templateFileEntity.getFilePath() + File.separator + templateFileEntity.getFileName();
            // 设置模板名
            dataModel.put("templateName", templateName);
            // 模板内容
            String templateContent = GenUtil.getFileContent(generatorProperties, templateFileEntity);
            // 生成内容
            String content = TemplateUtil.getContent(templateContent, dataModel);
            return new PreviewVO(templateFileEntity.getFileType(), content);
        } catch (Exception e) {
            log.error("生成文件内容失败, 表名: {}, 文件类型: {}, 异常信息: {}", previewQuery.getTableName(), templateFileEntity.getId(), e.getMessage());
            throw new BusinessException(ResultCode.COMMON_FAIL.getCode(), "生成模板内容失败: " + e.getMessage());
        }
    }

    @Override
    public TableDefaultVO getDefaultData() {
        TableDefaultVO tableDefaultVO = new TableDefaultVO();
        // 获取默认的数据源
        List<DatasourceEntity> datasourceEntityList = dataSourceService.list(new LambdaQueryWrapper<DatasourceEntity>().eq(DatasourceEntity::getSelected, true));
        if (!CollectionUtils.isEmpty(datasourceEntityList)) {
            tableDefaultVO.setDatasourceId(datasourceEntityList.get(0).getId());
        }
        // 设置默认工程
        List<ProjectEntity> projectEntityList = projectService.list(new LambdaQueryWrapper<ProjectEntity>().eq(ProjectEntity::getSelected, true));
        if (!CollectionUtils.isEmpty(projectEntityList)) {
            tableDefaultVO.setProjectId(projectEntityList.get(0).getId());
        }
        // 设置默认模板组
        List<TemplateGroupEntity> templateGroupEntityList = templateGroupService.list(new LambdaQueryWrapper<TemplateGroupEntity>().eq(TemplateGroupEntity::getSelected, true));
        if (!CollectionUtils.isEmpty(templateGroupEntityList)) {
            tableDefaultVO.setTemplateGroupId(templateGroupEntityList.get(0).getId());
        }

        return tableDefaultVO;
    }

    /**
     * 填充列表
     *
     * @param dataModel     数据模型
     * @param genDataSource 数据源
     * @param tableName     表名
     * @return 字段信息
     */
    private List<FieldInfo> fillList(Map<String, Object> dataModel, GenDataSource genDataSource, String tableName) {
        // 生成表字段列表
        List<FieldInfo> fieldList = GenUtil.getTableFieldList(genDataSource, tableName);
        // 设置基类
        setBaseClass(dataModel, fieldList);
        // 填充字段列表
        fillFieldList(dataModel, fieldList);
        // 设置主键类型
        setPkType(dataModel, fieldList);
        // 设置字段列表
        dataModel.put("fieldList", fieldList);
        return fieldList;
    }

    /**
     * 设置主键类型
     * 如果存在多个主键, 则取第一个
     *
     * @param dataModel 数据模型
     * @param fieldList 字段列表
     */
    private void setPkType(Map<String, Object> dataModel, List<FieldInfo> fieldList) {
        for (FieldInfo fieldInfo : fieldList) {
            // 判断是否为主键
            if (fieldInfo.isPrimaryKey()) {
                dataModel.put("pkType", fieldInfo.getAttrType());
            }
        }
    }

    /**
     * 设置基类信息
     *
     * @param dataModel 数据模型
     * @param fieldList 字段列表
     */
    private void setBaseClass(Map<String, Object> dataModel, List<FieldInfo> fieldList) {

        // 基类
        BaseClassEntity baseClassEntity = baseClassService.getById(1);
        BaseClassInfo baseClassInfo = new BaseClassInfo(baseClassEntity.getClassName(), baseClassEntity.getPackageName());
        dataModel.put("baseClass", baseClassInfo);

        // 基类字段
        String[] fields = baseClassEntity.getFields().split(",");

        // 标注为基类字段
        for (FieldInfo fieldInfo : fieldList) {
            if (ArrayUtil.contains(fields, fieldInfo.getFieldName())) {
                // 标记为基类字段
                fieldInfo.setBaseField(true);
            }
        }
    }

    /**
     * 填充字段列表
     *
     * @param dataModel 数据模型
     * @param fieldList 字段列表
     */
    private void fillFieldList(Map<String, Object> dataModel, List<FieldInfo> fieldList) {
        // 导入列表
        List<String> importList = new ArrayList<>();
        // form 表单
        List<FieldInfo> formList = new ArrayList<>();
        // 字段类型信息
        Map<String, FieldTypeInfo> map = fieldTypeService.getMap();
        // 遍历
        for (FieldInfo fieldInfo : fieldList) {
            // 填充属性类型
            FieldTypeInfo fieldTypeInfo = map.get(fieldInfo.getFieldType());
            if (Objects.nonNull(fieldTypeInfo)) {
                fieldInfo.setAttrType(fieldTypeInfo.getAttrType());
                // 如果包名不为空且不在父类且未加入
                String packageName = fieldTypeInfo.getPackageName();
                if (StringUtils.hasLength(packageName) && !fieldInfo.isBaseField() && !importList.contains(packageName)) {
                    importList.add(packageName);
                }
            } else {
                log.warn("未知字段类型: {}", fieldInfo.getFieldType());
            }
            // 填充属性名
            String fieldName = fieldInfo.getFieldName();
            // 删除前缀 is_
            if (fieldName.startsWith(GenConstant.PREFIX_IS)) {
                fieldName = fieldName.replace(GenConstant.PREFIX_IS, "");
            }
            // 驼峰小写
            String attrName = NamingCase.toCamelCase(fieldName);
            fieldInfo.setAttrName(attrName);

            // 设置表单类型
            FormTypeEnum formTypeEnum = FormTypeEnum.convert(fieldInfo.getFieldType());
            fieldInfo.setFormType(formTypeEnum);

            // 只要不是基类的字段都添加到form
            if (!fieldInfo.isBaseField()) {
                formList.add(fieldInfo);
            }
        }
        // 设置导入列表
        dataModel.put("importList", importList);
        // 设置表单字段
        dataModel.put("formList", formList);
    }

    /**
     * 获取渲染的数据模型
     *
     * @param previewQuery 预览信息
     */
    @Override
    public Map<String, Object> getDataModel(PreviewQuery previewQuery) throws Exception {
        // 初始化配置信息
        GenDataSource genDataSource = dataSourceService.getBySourceId(previewQuery.getDatasourceId());
        // 查询工程信息
        ProjectEntity projectEntity = projectService.getById(previewQuery.getProjectId());
        // 表名
        String tableName = previewQuery.getTableName();
        // 表信息
        TableVO tableVO = GenUtil.getTable(genDataSource, tableName);
        // 数据模型
        Map<String, Object> dataModel = new HashMap<>();
        // 获取属性配置
        Map<String, String> map = propItemService.queryByGroupId(projectEntity.getPropGroupId());

        // 设置前缀
        // dao前缀
        String daoPrefix = map.getOrDefault("dao_prefix", "");
        // converter 前缀
        String converterPrefix = map.getOrDefault("'converter_prefix'", "");
        // service 前缀
        String servicePrefix = map.getOrDefault("'service_prefix'", "");
        // 接口版本号
        String urlVersion = map.getOrDefault("'url_version'", "");
        // 作者
        String author = map.getOrDefault("'author'", "");

        // 项目信息
        String allPackageName = projectEntity.getPackageName();
        dataModel.put("package", GenUtil.getPackageName(allPackageName));
        // 大写驼峰
        String className = NamingCase.toPascalCase(tableName);
        dataModel.put("className", StrUtil.lowerFirst(className));
        dataModel.put("ClassName", className);
        // 模块名称
        String moduleName = GenUtil.getModuleName(allPackageName);
        dataModel.put("moduleName", moduleName);
        dataModel.put("ModuleName", StrUtil.upperFirst(moduleName));
        // 功能名
//        String functionName = GenUtil.getFunctionName(tableName);
        String functionName = StrUtil.lowerFirst(className);
        dataModel.put("functionName", functionName);
        dataModel.put("FunctionName", StrUtil.upperFirst(functionName));
        // dao 类名 {daoPrefix}{ClassName}
        dataModel.put("daoClassName", daoPrefix + className);
        // dao 类名 {daoPrefix}{ClassName}
        dataModel.put("converterClassName", converterPrefix + className);
        // dao 类名 {daoPrefix}{ClassName}
        dataModel.put("serviceClassName", servicePrefix + className);
        // 接口 {moduleName}/{urlVersion}/{tableName}"
        dataModel.put("urlPath", moduleName + File.separator + urlVersion + File.separator + functionName);
        // 包路径
        dataModel.put("packagePath", allPackageName.replace(".", File.separator));

        // 作者信息
        dataModel.put("author", author);
        dataModel.put("datetime", DateTimeUtil.time2String(LocalDateTime.now()));

//        dataModel.put("formLayout", table.getFormLayout());

//        // 设置字段分类
//        setFieldTypeList(dataModel, table);

        // 表信息
        dataModel.put("tableName", tableVO.getName());
        dataModel.put("tableComment", tableVO.getComment());

        // 填充字段信息列表, 导入列表
        List<FieldInfo> fieldList = fillList(dataModel, genDataSource, tableName);
        // 填充查询列表 - 初始状态为空
        List<FieldInfo> queryList = new ArrayList<>();
        dataModel.put("queryList", queryList);
        // 表格列表
        List<FieldInfo> gridList = new ArrayList<>(fieldList);
        dataModel.put("gridList", gridList);
//        pkType
        // 生成路径
//        dataModel.put("backendPath", table.getBackendPath());
//        dataModel.put("frontendPath", table.getFrontendPath());

        return dataModel;
    }

}